# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: cascade_prober.py
  @time: 2021/7/5 11:28
  @desc:
"""
import velox
from decimal import Decimal
import time
from utils.singleton_util import singleton

PR_INIT = 500
PR_MOVE = 501
PR_RELMOVE = 502
PR_RELRETURN = 503
PR_CHUCKUP = 504
PR_CHUCKDOWN = 509
PR_LOAD = 505
PR_UNLOAD = 506
PR_INK = 507

# define prober related fail error
PrInitFail = 21803
PrMoveFail = 21804
PrChuckFail = 21805
PrInkFail = 21806

# Prober type define
FAKE_PROBER = 0
HECH_PROBER = 1
NO_ERR = 0


@singleton
class CascadeProber:
    def __init__(self, address="192.168.1.100", port=1412):
        super().__init__()
        self.address = address
        self.port = port



    def dispatch_fun(self, prb_opt):
        if prb_opt == PR_INIT:
            return self.move_first_die()
        elif prb_opt == PR_MOVE:
            return self.move_next_die()
        elif prb_opt == PR_RELMOVE:
            return NO_ERR
        elif prb_opt == PR_RELRETURN:
            return NO_ERR
        elif prb_opt == PR_CHUCKUP:
            return self.chuck_up()
        elif prb_opt == PR_CHUCKDOWN:
            return self.chuck_down()
        elif prb_opt == PR_LOAD:
            return self.chuck_load()
        elif prb_opt == PR_UNLOAD:
            return self.chuck_unload()

    def read_chuck_status(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadChuckStatus()

    def go_to_wafer_home(self):

        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.GoToWaferHome()

    # 设置bin值
    def bin_map_die(self, bin_value: int):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.BinMapDie(int(bin_value))

    def set_probe_home(self, probe_num=1):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.SetProbeHome(probe_num)

    def get_subdie_label(self, site):

        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            subdie_label = velox.GetSubDieLabel(0, 0, Site=site)
            return subdie_label if subdie_label else "test"

    def get_die_data_as_num(self, die_index=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetDieDataAsNum(die_index)

    def get_die_data_as_col_row(self, die_x=0, die_y=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetDieDataAsColRow(die_x, die_y)

    @property
    def get_subdie_label_as_num(self, die_index=0, site=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetSubDieLabelAsNum(die_index, site)

    def get_subdie_data(self, subdie=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetSubDieData(subdie)

    def get_subdie_status(self, subdie=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetSubDieStatus(subdie)

    def get_subdie_data_as_col_row(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetSubDieDataAsColRow(0, 0, 0)

    def get_wafer_info(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.GetWaferInfo()

    # 清除所有的bin值
    def clear_all_bins(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.ClearAllBins()

    def step_first_die(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.StepFirstDie(1)

    def step_next_die(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.StepNextDie()

    def step_to_die(self, die_number, subdie_number=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.StepToDie(die_number, subdie_number)

    def step_next_subdie(self, site=0):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.StepNextSubDie(site)

    # chuck分离
    def move_chuck_separation(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.MoveChuckSeparation()

    # chuck接触
    def move_chuck_contact(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.MoveChuckContact()

    def move_chuck_unload(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.MoveChuckLoad("1")

    def read_chuck_index(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadChuckIndex()

    def read_map_position(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadMapPosition()

    def move_chuck_transfer(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.MoveChuckTransfer()

    def read_chuck_therm_scale(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadChuckThermoScale()

    def readSensor(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadSensor()

    def move_probe_separation(self, probe_number: int):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.MoveProbeSeparation(probe_number)

    def move_probe_contact(self, probe_number: int):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.MoveProbeContact(probe_number)

    # 移动chuck的Z轴方向到安全的位置
    def move_chuck_z_safe(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            velox.MoveChuckZSafe()

    # 移动probeZ轴方向的距离
    def move_probe_z(self, probe_number: int, z_value: Decimal, Velocity=70):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.MoveProbeZ(probe_number, z_value, "R", "Y", Velocity)

    # 以相对的距离移动x、y
    def move_probe(self, probe_number: int, x_value: Decimal, y_value: Decimal, Velocity=70):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port):
            return velox.MoveProbe(probe_number, x_value, y_value, "R", "Y", Velocity)

    def move_probe_home(self, probe_number: int, x_value: Decimal = 0, y_value: Decimal = 0, Velocity=100):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port):
            return velox.MoveProbe(probe_number, x_value, y_value, "H", "Y", Velocity)

    def read_probe_status(self, probe_num=1):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return velox.ReadProbeStatus(probe_num)

    #############################################################################################################

    def get_optical_probe_status(self, optical_positioner="H1"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("GetOpticalProbeStatus", optical_positioner)

    # 光探针操作部分
    def move_optical_probe(self, probe_alias: str, x_value: Decimal, y_value: Decimal):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            msgServer.sendSciCommand("MoveOpticalProbe", probe_alias, x_value, y_value, "R")

    # 光探针Z轴定位
    def move_optical_probe_z(self, probe_alias: str, z_value: Decimal):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            msgServer.sendSciCommand("MoveOpticalProbeZ", probe_alias, z_value, "R")

    def stop_sip_tools(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            msgServer.sendSciCommand("StopSiPTools")

    def area_scan(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("AreaScan", 1, 1)

    def gradient_search(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("GradientSearch", 1, 1,"inf")

    def get_num_optical_subdie(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("GetNumOpticalSubDie")

    def move_optical_subdie_pos(self, subdie_label, optical_positioner_id):
        """
        :param subdie_label:subdienumber或者subdieid
        :param positioner_id:探针的idoptical_positioner ID : W=West, E=East, S=South, H1=Hex(1), H2=Hex(2), H3=Hex(3), P1=Pos(1),
                            P2=Pos(2),...P6=Pos(6)S
        :return:
        """
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("MoveOpticalSubDiePos", subdie_label, optical_positioner_id)

    def move_optical_subdie(self, subdie_label, scope="H1"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("MoveOpticalSubDie", subdie_label, scope)

    def align_optical_probes(self, input_state, output_state):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            result = msgServer.sendSciCommand("AlignOpticalProbes", "", "", 10, input_state, output_state)
            return int(result[0])

    def get_optical_subdie_data(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("GetOpticalSubDieData", 1, "W")

    def set_optical_probe_home(self, optical_positioner="H1"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("SetOpticalProbeHome", optical_positioner)

    def move_optical_probe_home(self, optical_positioner="E"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("MoveOpticalProbe", optical_positioner, 0, 0, "H")

    def move_optical_separation_height(self, optical_positioner="H1"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("MoveOpticalSeparationHeight", optical_positioner)

    def move_optical_probe_height(self, optical_positioner="H1"):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("MoveOpticalProbeHeight", optical_positioner)

    def recenter_optical_probe(self, optical_positioner):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("RecenterOpticalProbe", optical_positioner)

    def search_first_light(self):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("SearchFirstLight", 1, 1)

    def find_optical_probe_height(self, optical_positioner, fiber_height=40):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("FindOpticalProbeHeight", optical_positioner, fiber_height)

    def set_optical_probe_height(self, optical_positioner):
        with velox.MessageServerInterface(ipaddr=self.address, targetSocket=self.port) as msgServer:
            return msgServer.sendSciCommand("SetOpticalProbeHeight", optical_positioner)


if __name__ == "__main__":
    """
    H1左H2南P1右P2北
    """
    start = time.time()
    print(start)
    address = "127.0.0.1"
    cp = CascadeProber(address=address)
    try:
        while True:
            cp.step_next_die()
            print(hash(cp))
    except Exception as e:
        print(e)
    # cp.stop_sip_tools()

    # print(cp.get_die_data_as_num(1))
    # for i in range(30):
    #     print(cp.area_scan())
    finally:
        print(time.time() - start)